解medium及以下级的一次可以出结果,hard级的一般要试一次,即从二选一的结果中挑一个作为已知值,very hard级要试两三次。除了试解,我现在还没有想出什么简单的好法子。
#include<iostream>
#include<fstream>
#include<iomanip>
using namespace std;
const int test[10]={511,1,2,4,8,16,32,64,128,256};
void sub(int &a, int b){
int i;
for(i=1; i<10; ++i)
if(a&test[i] && b&test[i])
a-=test[i];
}
int main(int argc, char* argv[]){
if(argc!=2){
cout<<"Usage: sudoku in-file"<<endl;
cout<<" example file contents:"<<endl;
cout<<" 0 5 0 0 1 4 0 3 0"<<endl;
cout<<" 0 0 2 0 7 0 0 4 0"<<endl;
cout<<" 0 1 0 0 0 8 0 0 0"<<endl;
cout<<" 0 2 9 0 4 5 3 0 0"<<endl;
cout<<" 0 0 7 0 8 0 6 0 0"<<endl;
cout<<" 0 0 1 3 6 0 5 2 0"<<endl;
cout<<" 0 0 0 4 0 0 0 6 0"<<endl;
cout<<" 0 7 0 0 2 0 8 0 0"<<endl;
cout<<" 0 9 0 8 5 0 0 1 0"<<endl;
cout<<" Position of 0s are to be filled."<<endl;
return 1;
}
ifstream fin(argv[1]);
int pro[10][10], ref[10][10], i,j,k,t,nz(0),lrb,lre,lcb,lce,m,n,old;
cout<<"Below is your problem:"<<endl;
for(i=1; i<10; ++i){
for(j=1; j<10; ++j){
fin>>pro[i][j];
if(pro[i][j]==0){
++nz;
ref[i][j]=test[0];
}else{
ref[i][j]=test[pro[i][j]];
}
cout<<setw(5)<<pro[i][j];
}
cout<<endl;
}
old=nz;
while(nz>0){
for(i=1; i<10; ++i)
for(j=1; j<10; ++j){
if(pro[i][j]==0){
//Any filled row number?
for(k=1; k<10; ++k){
t=pro[k][j];
if(t>0)if(test[t]&ref[i][j])ref[i][j]-=test[t];
}
//Column
for(k=1; k<10; ++k){
t=pro[i][k];
if(t>0)if(test[t]&ref[i][j])ref[i][j]-=test[t];
}
//Local square
if(i>6){
lrb=7;
lre=10;
}else if(i>3){
lrb=4;
lre=7;
}else{
lrb=1;
lre=4;
}
if(j>6){
lcb=7;
lce=10;
}else if(j>3){
lcb=4;
lce=7;
}else{
lcb=1;
lce=4;
}
for(m=lrb; m<lre; ++m)
for(n=lcb; n<lce; ++n){
t=pro[m][n];
if(t!=0)if(test[t]&ref[i][j])ref[i][j]-=test[t];
}
//Advanced
if(pro[i][j]==0){
//check if any unique number of multiple choices in this row
t=ref[i][j];
for(k=1;k<10;++k){
if(k==i)continue;
sub(t,ref[k][j]);
}
if(t>0)ref[i][j]=t;
//column
t=ref[i][j];
for(k=1;k<10;++k){
if(k==j)continue;
sub(t,ref[i][k]);
}
if(t>0)ref[i][j]=t;
//local square
t=ref[i][j];
for(m=lrb; m<lre; ++m)
for(n=lcb; n<lce; ++n){
if(m==i && n==j)continue;
sub(t,ref[m][n]);
}
if(t>0)ref[i][j]=t;
}
//Check if can fill now
t=0;
for(k=1; k<10; ++k)
if(ref[i][j]&test[k]){
++t;
m=k;
}
if(t==1){
pro[i][j]=m;
--nz;
}
}
}
if(old==nz){
cout<<endl<<"Algorithm need to be improved."<<endl<<endl;
break;
}
old=nz;
}
cout<<endl<<"Answer up to now:"<<endl;
for(i=1; i<10; ++i){
for(j=1; j<10; ++j){
if(pro[i][j]>0){
cout<<pro[i][j];
if(j<9)cout<<" ";
}else{
t=0;
for(k=1; k<10; ++k)
if(test[k]&ref[i][j]){
cout<<k;
++t;
}
if(j<9)for(k=0; k<8-t; ++k)cout<<' ';
}
}
cout<<endl;
}
return 0;
}